剛學一點 Go,
除了能夠使用別人寫好的 modules,
為了程式碼的可擴充性,也需要理解 Design Patterns。
今天搭配 Github 上的程式碼來學習各種「工廠」的設計模式~
大一剛學 Java 時,學到一些 interface 的概念,
也接觸到 Design Patterns 的書,
但實在難以理解製造出會叫的鴨子跟未來寫網頁、寫應用程式的關聯?
設計模式,是別人研究出來,怎麼樣寫程式能達到好擴充的方法。
因為需求會變動,
如果新增一個功能就要增加非常多行程式碼,
或是新增程式碼常常導致舊功能出錯,
十分浪費時間心力。
我覺得學習 Design Patterns 不是一件容易的事,
運用到很多抽象化的概念。
而就算理解一個設計模式,
接下來要能夠融會貫通的使用在適合的情境,除了經驗也需要刻意留心。
本篇參考這個 Github repo 的程式碼:Go 语言设计模式 來理解設計模式。
而這本 Gitbook 設計模式學習筆記 講解前面幾個模式也算是簡單易懂,並附上類別圖和程式碼,值得參考。
注意 Go 裡面沒有 object / class,
這邊如果提到物件通常是 Go 中 implement interface 的 struct
根據傳入的參數回傳指定物件
package main
import "fmt"
type Animal interface {
Say() string
}
func newAnimal(t int) Animal {
// 如果想增加不同動物,需要在這裡改
// 不符合 SOLID 的 O(開放封閉原則)
if t == 1 {
return Dog{}
} else if t == 2{
return &Cat{}
}
return nil
}
type Cat struct {}
type Dog struct {}
func (*Cat) Say() string {
return "meow!"
}
func (Dog) Say() string {
return "bark!"
}
func main() {
a1 := newAnimal(1)
fmt.Println("type 1 Animal")
fmt.Println(a1.Say())
a2 := newAnimal(2)
fmt.Println("type 2 Animal")
fmt.Println(a2.Say())
}
規定一個工廠該有的樣子(interface),要能夠製造不同商品(instance)就各自去實現不同的工廠
repo 中的程式碼以 Operator 來舉例。04_factory_method
OperatorFactory
是工廠 interface,合格的工廠應該要實作一個會製造出 Operator
的 Create
method。Operator
則是定義了 SetA
SetB
Result
三個 method。SetA
SetB
都是對 struct OperatorBase
定義的 method,OperatorBase
中有 a b 兩整數。
提醒 Go 中沒有繼承,就用 nested struct 達到類似效果:
type PlusOperator struct {
*OperatorBase
}
工廠產生的物件「有關聯」
完整程式碼:05_abstract_factory
DAOFactory
是抽象工廠的 interface,要實作這個工廠,底下就要使用 CreateOrderMainDAO()
與 CreateOrderDetailDAO()
分別實作兩個子工廠 OrderMainDAO
與 OrderDetailDAO
。
這裏就存有訂單主紀錄與詳情紀錄的抽象關係。
type OrderMainDAO interface {
SaveOrderMain()
}
type OrderDetailDAO interface {
SaveOrderDetail()
}
type DAOFactory interface {
CreateOrderMainDAO() OrderMainDAO
CreateOrderDetailDAO() OrderDetailDAO
}
RDB 工廠的實作環節,
首先先做一個 RDB 抽象工廠,
裡面要去實作 使用 RDB 儲存主紀錄和詳情紀錄的實現方式。
XML 的工廠實作也一樣,就是 method 裡面的實作細節不同而已
// 使用 RDB 存主紀錄
type RDBMainDAO struct{}
func (*RDBMainDAO) SaveOrderMain() {
fmt.Print("rdb main save\n")
}
// 使用 RDB 存詳情紀錄
type RDBDetailDAO struct{}
func (*RDBDetailDAO) SaveOrderDetail() {
fmt.Print("rdb detail save\n")
}
// RDB 的抽象工廠與實現
type RDBDAOFactory struct{}
func (*RDBDAOFactory) CreateOrderMainDAO() OrderMainDAO {
return &RDBMainDAO{}
}
func (*RDBDAOFactory) CreateOrderDetailDAO() OrderDetailDAO {
return &RDBDetailDAO{}
}